package com.corner.utils.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;

import com.corner.R;


/**
 * Created by 韩炜伟 on 15-4-24.
 */
public class ImageCut extends ImageView {
    public static final int DRAG = 1;
    public static final int ZOOM = 2;
    public static final int NONE = 3;
    private static final float K = 1.5f;
    private PointF startPoint;
    private PointF newPosition;
    private PointF downPosition;
    private PointF midPoint;
    private int mode;
    private Matrix imgMatrix;
    private Matrix savedMatrix;
    private Matrix startMatrix;
    private double oldDistance;
    private double newDistance;
    private boolean result;
    private String bitmapPath;
    private float left;
    private float top;
    private Bitmap bitmap;

    private Paint borderPaint;
    /**
     * 整个view的宽高
     */
    private int viewHeight;
    private int viewWidth;
    /**
     * bitmap的宽高
     */
    private int width;
    private int height;

    private Rect border;
    private Paint transPaint;
    private boolean hasInit = false;
    private float showAllScale;

    public ImageCut(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ImageCut(Context context) {
        super(context);
    }

    public ImageCut(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * @return 0：left/width 1:top/height 2：right/width 3:bottom/height
     */
    public float[] getScale() {
        float[] result = new float[4];
        // 选中正方形左上角点的left占整个bitmap宽的比例
        float[] values = new float[9];
        imgMatrix.getValues(values);
        float currWidth = values[0] * width;
        float currHeight = values[0] * height;
        if (currWidth < border.width())
            result[0] = 0;
        else
            result[0] = -values[2] / currWidth;
        if (currHeight <= border.height())
            result[1] = 0;
        else
            result[1] = (-values[5] + border.top) / currHeight;
        if (currWidth < border.width())
            result[2] = 1;
        else
            result[2] = (-values[2] + viewWidth) / currWidth;
        if (currHeight <= border.height())
            result[3] = 1;
        else
            result[3] = (-values[5] + border.bottom) / currHeight;
        return result;
    }

    /**
     * 初始化bitmap，对bitmap进行缩放，获取到能居中放置的bitmap
     */
    private void initBitmap() {
        // 1.居中放置图片
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        opts.inPreferredConfig = Config.ARGB_8888;
        // 只加载bitmap的宽高
        bitmap = BitmapFactory.decodeFile(bitmapPath, opts);
        width = opts.outWidth;
        height = opts.outHeight;
        // 获取View的宽高
        viewHeight = getMeasuredHeight();
        viewWidth = getMeasuredWidth();
        // 计算缩放的比例
        float scale = ((float) width) / viewWidth;
        // 计算bitmap放置在View中的位置


        opts.inJustDecodeBounds = false;
        opts.inSampleSize = (int) scale == 0 ? 1 : (int) scale;
        // 获取缩放适当的bitmap，以防oom
        // 注意：加载的bitmap不是宽高为width height，下一步要对其缩放
        bitmap = BitmapFactory.decodeFile(bitmapPath, opts);

        width = bitmap.getWidth();
        height = bitmap.getHeight();
        scale = ((float) width) / viewWidth;


        left = 0;
        top = (viewHeight - height / scale) / 2;

        imgMatrix.postScale(1 / scale, 1 / scale);
        imgMatrix.postTranslate(left, top);
        setImageBitmap(bitmap);
        setScaleType(ScaleType.MATRIX);
        setImageMatrix(imgMatrix);
        savedMatrix.set(imgMatrix);
        startMatrix.set(imgMatrix);

    }

    private void initBorder() {
        border = new Rect(0, (viewHeight - viewWidth) / 2, viewWidth, (viewHeight + viewWidth) / 2);
        // 设置画笔
        borderPaint = new Paint();
        borderPaint.setStrokeWidth(2);
        borderPaint.setColor(getResources().getColor(R.color.gray_divider));
        borderPaint.setAlpha(255);
        // 描边
        borderPaint.setStyle(Paint.Style.STROKE);
        borderPaint.setAntiAlias(true);

    }

    /**
     * 画边框
     *
     * @param canvas
     */
    private void drawBorder(Canvas canvas) {
        // 绘制方框
        canvas.drawLine(border.left, border.top, border.right, border.top, borderPaint);
        canvas.drawLine(border.left, border.bottom, border.right, border.bottom, borderPaint);
    }

    public void setBitmapPath(String bitmapPath) {
        this.bitmapPath = bitmapPath;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (bitmapPath == null) {
            return;
        }
        if (!hasInit) {
            init();
            initBitmap();
            initBorder();
            showAllScale = getShowAllScale();
            hasInit = true;
        }
        // 绘制白色背景
        canvas.drawColor(0xffffffff);
        //绘制图片
        super.onDraw(canvas);
        // 绘制边框
        drawBorder(canvas);
        //绘制透明图层
        drawTransparent(canvas);
    }

    /**
     * 绘制透明图层
     *
     * @param canvas
     */
    private void drawTransparent(Canvas canvas) {
        if (transPaint == null) {
            transPaint = new Paint();
            transPaint.setColor(0xa0ffffff);
            transPaint.setAntiAlias(true);
        }
        canvas.drawRect(0, 0, viewWidth, border.top, transPaint);
        canvas.drawRect(0, border.bottom, viewWidth, viewHeight, transPaint);
    }

    private void init() {
        startPoint = new PointF();
        newPosition = new PointF();
        downPosition = new PointF();
        midPoint = new PointF();
        savedMatrix = new Matrix();
        imgMatrix = new Matrix();
        startMatrix = new Matrix();
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (bitmap == null) {
            return true;
        }
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                startPoint.set(event.getX(), event.getY());
                mode = DRAG;
                result = false;
                downPosition.set(startPoint);
                break;
            case MotionEvent.ACTION_UP:
                mode = NONE;
                if (!result) {
                    this.performClick();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                switch (mode) {
                    case DRAG:
                        newPosition.set(event.getX(), event.getY());
                        result = Math.sqrt(Math.pow(newPosition.x - downPosition.x, 2) + Math.pow(newPosition.y - downPosition.y, 2)) > 10f;
                        imgMatrix.set(savedMatrix);
                        imgMatrix.postTranslate(K * (newPosition.x - startPoint.x), K * (newPosition.y - startPoint.y));
                        ruleImgMatrix();
                        setImageMatrix(imgMatrix);
                        savedMatrix.set(imgMatrix);
                        startPoint.set(newPosition);
                        break;
                    case ZOOM:
                        newDistance = Math.sqrt(Math.pow(event.getX(0) - event.getX(1), 2) + Math.pow(event.getY(0) - event.getY(1), 2));
                        if (newDistance > 10f) {
                            result = true;
                            float scale = (float) (newDistance / oldDistance);
                            imgMatrix.set(savedMatrix);
                            imgMatrix.postScale(scale, scale, midPoint.x, midPoint.y);
                            ruleImgMatrix();
                            setImageMatrix(imgMatrix);
                            savedMatrix.set(imgMatrix);
                            oldDistance = newDistance;
                        } else {
                            result = false;
                        }
                        break;
                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                oldDistance = Math.sqrt(Math.pow(event.getX(0) - event.getX(1), 2) + Math.pow(event.getY(0) - event.getY(1), 2));
                if (oldDistance > 10f) {
                    mode = ZOOM;
                    midPoint.set((event.getX(0) + event.getX(1)) / 2, (event.getY(0) + event.getY(1)) / 2);
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                break;
        }
        return true;
    }


    private void ruleImgMatrix() {
        float[] values = new float[9];
        float[] startValues = new float[9];
        startMatrix.getValues(startValues);
        imgMatrix.getValues(values);
        if (values[0] <= 1 / showAllScale) {
            values[0] = values[4] = 1 / showAllScale;
        }
        if (values[0] > getMaxScale() * startValues[0]) {
            values[0] = values[4] = getMaxScale() * startValues[0];
            float[] savedValues = new float[9];
            savedMatrix.getValues(savedValues);
            values[2] = savedValues[2];
            values[5] = savedValues[5];
        }
        if (viewWidth <= width * values[0] && values[2] < viewWidth - width * values[0]) {
            values[2] = viewWidth - width * values[0];
        } else if (values[2] > 0 && viewWidth <= width * values[0]) {
            values[2] = 0;
        } else if (viewWidth > width * values[0]) {
            values[2] = (viewWidth - width * values[0]) / 2;
        }

        int borderHeight = border.height();
        if (borderHeight < height * values[0] && values[5] < border.bottom - height * values[0]) {
            values[5] = border.bottom - height * values[0];
        } else if (values[5] > border.top && borderHeight < height * values[0]) {
            values[5] = border.top;
        } else if (borderHeight >= height * values[0]) {
            values[5] = (viewHeight - height * values[0]) / 2;
        }
        imgMatrix.setValues(values);
    }

    protected int getMaxScale() {
        return 2;
    }

    /**
     * 显示全部
     */
    public void showAll() {

        float[] values = new float[9];
        imgMatrix.getValues(values);
        if (Math.abs(values[0] - 1 / showAllScale) < 0.001) {
            imgMatrix.set(startMatrix);
            setImageMatrix(imgMatrix);
            savedMatrix.set(imgMatrix);
        } else {
            //显示全部
            imgMatrix.reset();
            imgMatrix.postScale(1 / showAllScale, 1 / showAllScale);
            imgMatrix.postTranslate(left, top);
            setImageMatrix(imgMatrix);
            savedMatrix.set(imgMatrix);
        }
    }

    private float getShowAllScale() {
        // 计算缩放的比例
        float scaleX = ((float) width) / viewWidth;
        float scaleY = ((float) height) / border.height();
        float scale;
        // 计算bitmap放置在View中的位置
        if (scaleX < scaleY) {
            left = (viewWidth - width / scaleY) / 2.0f;
            top = border.top;
            scale = scaleY;
        } else {
            left = 0;
            top = border.top + (border.height() - height / scaleX) / 2.0f;
            scale = scaleX;
        }
        return scale;
    }
}
